package main

import (
	"bytes"
	"crypto/tls"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"github.com/sbabiv/xml2map"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"regexp"
	"strings"
)

func RunPom() {
	log.SetFlags(log.Lshortfile | log.LstdFlags)
	var tmpFile = "pom.xml"
	data, _ := json.Marshal(readXml(tmpFile))
	log.Printf("%s \n\n\n", string(data))
}

type Dependency struct {
	XMLName    xml.Name `xml:"dependency" json:"-"`
	GroupId    string   `xml:"groupId" json:"groupId"`
	ArtifactId string   `xml:"artifactId" json:"artifactId"`
	Version    string   `xml:"version" json:"version"`
}

type Dependencies struct {
	XMLName        xml.Name     `xml:"dependencies"`
	DependencyList []Dependency `xml:"dependency"`
}

type DependencyManagement struct {
	XMLName      xml.Name     `xml:"dependencyManagement"`
	Dependencies Dependencies `xml:"dependencies"`
}

type Pom struct {
	XMLName              xml.Name             `xml:"project"`
	Dependencies         Dependencies         `xml:"dependencies"`
	DependencyManagement DependencyManagement `xml:"dependencyManagement"`
}

func readXml(filePath string) []Dependency {
	var dpList []Dependency
	log.Println("解析xml")
	data, err := ioutil.ReadFile(filePath)
	if err != nil {
		log.Println(err)
		return dpList
	}
	var pom Pom
	err = xml.Unmarshal(data, &pom)
	if err != nil {
		log.Println(err)
		return dpList
	}
	decoder := xml2map.NewDecoder(bytes.NewReader(data))
	result, err := decoder.Decode()
	if err != nil {
		log.Println(err)
		return dpList
	}
	property := make(map[string]string)
	for k, v := range result {
		if strings.Contains(k, ":") && strings.HasSuffix(k, "project") {
			prefix := k[:len(k)-len("project")-1]
			start := len(prefix) + 1
			properties := v.(map[string]any)[prefix+":properties"]
			for kk, vv := range properties.(map[string]any) {
				property[kk[start:]] = vv.(string)
			}
			break
		}
	}
	for _, dp := range append(pom.Dependencies.DependencyList, pom.DependencyManagement.Dependencies.DependencyList...) {
		dp = updateVersion(dp, property)
		dpList = append(dpList, dp)
	}
	log.Println("xml解析完成")
	return dpList
}

func updateVersion(dp Dependency, property map[string]string) Dependency {
	reg := regexp.MustCompile(`\${([\w._-]+)}`)
	result := reg.FindAllStringSubmatch(dp.GroupId, 1)
	var k string
	if len(result) > 0 && len(result[0]) > 1 {
		k = result[0][1]
	}
	if v, ok := property[k]; ok {
		dp.GroupId = strings.ReplaceAll(dp.GroupId, "${"+k+"}", v)
	}

	result = reg.FindAllStringSubmatch(dp.ArtifactId, 1)
	if len(result) > 0 && len(result[0]) > 1 {
		k = result[0][1]
	}
	if v, ok := property[k]; ok {
		dp.ArtifactId = strings.ReplaceAll(dp.ArtifactId, "${"+k+"}", v)
	}

	result = reg.FindAllStringSubmatch(dp.Version, 1)
	if len(result) > 0 && len(result[0]) > 1 {
		k = result[0][1]
	}
	if v, ok := property[k]; ok {
		dp.Version = strings.ReplaceAll(dp.Version, "${"+k+"}", v)
	}
	var s = dp.GroupId + dp.ArtifactId + dp.Version
	if strings.Contains(s, "${") {
		log.Println(s)
		return updateVersion(dp, property)
	}
	return dp
}

func DownloadFile(url string, newFilePath string) error {
	log.Println("正在下载文件", url)
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}
	req, _ := http.NewRequest("GET", url, bytes.NewBuffer([]byte{}))
	resp, err := client.Do(req)
	defer func() {
		if resp != nil {
			err = resp.Body.Close()
			if err != nil {
				log.Println(err)
			}
		}
		client.CloseIdleConnections()
	}()
	if err != nil {
		return err
	}
	result, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if resp.StatusCode != 200 {
		return errors.New(fmt.Sprintf("StatusCode: %d, ResponseData: %s", resp.StatusCode, string(result)))
	}
	err = ioutil.WriteFile(newFilePath, result, os.ModePerm)
	if err != nil {
		return err
	}
	log.Println("下载完成")
	return nil
}
